package ru.spb.osll.myfit.client.widget;

import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.VerticalPanel;
import ru.spb.osll.myfit.client.Mode;
import ru.spb.osll.myfit.client.event.PageEvent;
import ru.spb.osll.myfit.client.event.PageEvent.PageEventType;
import ru.spb.osll.myfit.common.Page;
import ru.spb.osll.myfit.common.PageElement;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

/**
 * Page widget.
 */
public class PageWidget extends Composite implements PageEventListener {

  private PageElementWidgetFactory m_pageElementWidgetFactory;
  private HashMap<String, String> m_variables = new HashMap<String, String>();
  private Page m_page;

  List<PageEventListener> m_listeners = new LinkedList<PageEventListener>();
  /**
   * Main panel. All page elements will be added in it.
   */
  private VerticalPanel m_elementsPanel;
  private VerticalPanel m_rootPanel;
  private TagPanelWidget m_tagPanelWidget = new TagPanelWidget();
  private Mode m_mode = Mode.VIEW;

  private String m_pagePath = "";

  public PageWidget(GWTWidgetFactory gwtWidgetFactory, String pagePath) {
    this(gwtWidgetFactory);
    m_pagePath = pagePath;
  }

  public PageWidget(GWTWidgetFactory gwtWidgetFactory) {
    m_pageElementWidgetFactory = new PageElementWidgetFactory(gwtWidgetFactory);
    m_rootPanel = gwtWidgetFactory.createVerticalPanel();
    m_rootPanel.setStyleName(IStyleConstants.TABLE_PANEL_STYLE);
    m_elementsPanel = gwtWidgetFactory.createVerticalPanel();
    m_elementsPanel.setSpacing(20);
    m_elementsPanel.setStyleName(IStyleConstants.TABLE_PANEL_STYLE);
    m_elementsPanel.setLayoutData(gwtWidgetFactory.createScrollPanel());
    m_tagPanelWidget.addStyleName("testTagsPanelWidget");
    m_rootPanel.add(m_tagPanelWidget);
    m_rootPanel.add(m_elementsPanel);
    initWidget(m_rootPanel);
  }

  public void setPage(final Page page) {
    m_variables = page.getParentVariables();
    m_tagPanelWidget.setTags(page.getTags());
    for (PageElement element : page.getElements()) {
      addPageElementWidget(element);
    }
  }

  public void addPageElementWidget(PageElement pageElement) {
    PageElementWidget pageElementWidget = m_pageElementWidgetFactory.getPageElementWidget(pageElement);
    if (pageElementWidget != null) {
      pageElementWidget.setPageEventListener(this);
      pageElementWidget.setMode(m_mode);
      m_elementsPanel.add(pageElementWidget);
      updateWidgets(null);
    }
  }

  public void addPageElementWidget(PageElement pageElement, int index) {
    PageElementWidget pageElementWidget = m_pageElementWidgetFactory.getPageElementWidget(pageElement);
    if (pageElementWidget != null) {
      pageElementWidget.setPageEventListener(this);
      pageElementWidget.setMode(m_mode);
      m_elementsPanel.insert(pageElementWidget, index);
      updateWidgets(null);
    }
  }

  public void clear() {
    m_elementsPanel.clear();
  }

  public void setMode(Mode mode) {
    m_mode = mode;
    if (mode == Mode.EDIT) {
      m_tagPanelWidget.setEnabled(true);
    } else {
      m_tagPanelWidget.setEnabled(false);
    }
    int widgetCount = m_elementsPanel.getWidgetCount();
    for (int i = 0; i < widgetCount; i++) {
      PageElementWidget pageElement = (PageElementWidget) m_elementsPanel.getWidget(i);
      pageElement.setMode(m_mode);
    }
  }

  public PageElementWidget getElementWidget(int index) {
    return (PageElementWidget) m_elementsPanel.getWidget(index);
  }

  public int getElementWidgetCount() {
    return m_elementsPanel.getWidgetCount();
  }

  public Page getPage() {
    Page page = new Page();
    int size = m_elementsPanel.getWidgetCount();
    for (int i = 0; i < size; i++) {
      PageElementWidget pageElementWidget = (PageElementWidget) m_elementsPanel.getWidget(i);
      PageElement pageElement = pageElementWidget.getPageElement();
      if (pageElement != null) {
        page.insert(pageElement);
      }
    }
    page.setTags(m_tagPanelWidget.getTags());
    page.setParentVariables(m_variables);
    return page;
  }

  public void deletePageElementWidget(PageElementWidget elementToDelete) {
    m_elementsPanel.remove(elementToDelete);
    if (elementToDelete instanceof DefineWidget)
      updateWidgets(null);
  }

  public void insertPageElement(PageElementWidget selectedWidget, PageElement elementToInsert, boolean isBefore) {
    int place = m_elementsPanel.getWidgetIndex(selectedWidget);// m_pagesWidgets.indexOf(selectedWidget);
    if (place == -1) {
      addPageElementWidget(elementToInsert);
    } else {
      if (!isBefore) {
        place++;
      }
      addPageElementWidget(elementToInsert, place);
    }
  }

  public void setOpen(boolean isOpen) {
    int pageWidgetsCount = m_elementsPanel.getWidgetCount();
    for (int i = 0; i < pageWidgetsCount; i++) {
      PageElementWidget elementWidget = (PageElementWidget) m_elementsPanel.getWidget(i);
      elementWidget.setOpen(isOpen);
    }
  }

  @Override
  public void actionPerformed(PageEvent event) {
    if (event.getType() == PageEventType.DEFINE_CHANGED) {
      updateWidgets(null);
    }
    if (event.getType() == PageEventType.DELETE_PAGE_ELEMENT) {
      deletePageElementWidget(event.getSource());

    } else {
      for (PageEventListener listener : m_listeners) {
        PageEvent newEvent = new PageEvent(event.getType(), event.isBefore(), event.getSource(), this);
        listener.actionPerformed(newEvent);
      }
    }
  }

  public int getWidgetCount() {
    return m_elementsPanel.getWidgetCount();
  }

  public PageElementWidget getPageElementWidget(int index) {
    return (PageElementWidget) m_elementsPanel.getWidget(index);
  }

  public PageElement removeWidget(int position) {
    PageElementWidget widget = (PageElementWidget) m_elementsPanel.getWidget(position);
    PageElement element = widget.getPageElement();
    m_elementsPanel.remove(position);
    return element;
  }

  public void addPageEventListener(PageEventListener listener) {
    m_listeners.add(listener);
  }

  public void removePageEventListener(PageEventListener listener) {
    m_listeners.remove(listener);
  }

  public String getPagePath() {
    return m_pagePath;
  }

  public void setPagePath(String pagePath) {
    m_pagePath = pagePath;
  }

  public void setVariables(HashMap<String, String> variables) {
    if (variables != null)
      m_variables = variables;
    else
      m_variables = new HashMap<String, String>();
  }

  public void updateWidgets(HashMap<String, String> current) {
    HashMap<String, String> currentVariables;
    if (current != null) currentVariables = current;
    else currentVariables = new HashMap<String, String>();

    currentVariables.putAll(m_variables);

    int pageWidgetsCount = m_elementsPanel.getWidgetCount();
    for (int i = 0; i < pageWidgetsCount; i++) {
      PageElementWidget widget = (PageElementWidget) m_elementsPanel.getWidget(i);
      if (widget instanceof DefineWidget) {
        DefineWidget define = (DefineWidget) widget;
        currentVariables.put(define.getName(), define.getValue());
      } else if (widget instanceof IncludeWidget) {
        IncludeWidget include = (IncludeWidget) widget;
        include.setVariables(null);
        include.updateWidgets(currentVariables);
      } else if (widget instanceof TableWidget) {
        TableWidget table = (TableWidget) widget;
        table.parseVariables(currentVariables);
      }
    }
  }

  /*
  Tries to add new tag and return true on success and false if such tag already exists
   */
  public boolean addTag(String tag) {
    return m_tagPanelWidget.createNewTag(tag);
  }

}
